/**
 * This file is a part of qloudgen-sec. 
 * You can redistribute qloudgen-sec and/or modify it under the terms of the Lesser GNU General Public License version 3. 
 * qloudgen-sec is distributed WITHOUT ANY WARRANTY. 
 *
 * See the Lesser GNU General Public License for more details at http://www.gnu.org/licenses/. 
 **/
package org.redisson.codec;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;

public class ValueSerializationCodec implements RedissonCodec {
    private Charset charset;
    private CharsetDecoder decoder;
    private CharBuffer chars;

    public ValueSerializationCodec() {
        charset = Charset.forName( "UTF-8" );
        decoder = charset.newDecoder();
        chars   = CharBuffer.allocate( 1024 );
    }

    @Override
    public Object decodeKey(ByteBuffer bytes) {
        chars.clear();
        bytes.mark();
        decoder.reset();
        //
        while ( decoder.decode( bytes , chars , true ) == CoderResult.OVERFLOW || decoder.flush( chars ) == CoderResult.OVERFLOW ) {
            chars = CharBuffer.allocate( chars.capacity() * 2 );
            bytes.reset();
        }
        //
        return chars.flip().toString();
    }

    @Override
    public Object decodeMapKey(ByteBuffer bytes) {
        return decodeKey(bytes);
    }

    @Override
    public byte[] encodeKey(Object key) {
        return ( ( String )key ).getBytes( charset );
    }

    @Override
    public byte[] encodeMapKey(Object key) {
        return encodeKey(key);
    }

    @Override
    public Object decodeValue(ByteBuffer bytes) {
        try {
            ByteArrayInputStream in = new ByteArrayInputStream(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.limit());
            ObjectInputStream inputStream = new ObjectInputStream(in);
            return inputStream.readObject();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public Object decodeMapValue(ByteBuffer bytes) {
        return decodeValue(bytes);
    }

    @Override
    public byte[] encodeValue(Object value) {
        try {
            ByteArrayOutputStream result = new ByteArrayOutputStream();
            ObjectOutputStream outputStream = new ObjectOutputStream(result);
            outputStream.writeObject(value);
            outputStream.close();
            return result.toByteArray();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public byte[] encodeMapValue(Object value) {
        return encodeValue(value);
    }
}